﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;

namespace Segmentation.Business
{
    public class JSEGAccessor
    {
        #region enum Mode

        public enum Mode { 
            Original = 1, 
            JModification1 = 2,
            JModification2 = 3,
            JModification3 = 4,
        };

        #endregion enum Mode
        
        #region Delegates

        public delegate void ReportHandler(string str);
        public delegate void ShowJImageHandler(int step, int TR, IntPtr J, int height, int width);

        #endregion Delegates

        #region CONSTS

        public const int CONSTQUANTTRESH = -1;
        public const int CONSTSCALES = -1;
        public const float CONSTMERGETRESH = 0.4f;

        #endregion CONSTS

        #region DllImports

        [DllImport("jseg.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        private static extern int ProcessImage(
                        [In, Out] byte[] inputImage,
                        int inputImageHeight,
                        int inputImageWidth,
                        [In, Out] byte[] colorMap,
                        [In, Out] byte[] regionMap,
                        int colorQuantizationThreshold,
                        int numberOfScales,
                        float regionMergeThreshold,
                        int mode,
                        ReportHandler funcReport,
                        ShowJImageHandler funcShowJImage);


        #endregion DllImports

        #region Fields

        private List<JImage> jImages;
        private byte[,] colorMap;
        private byte[,] regionMap;
        private int colorQuantizationThreshold;
        private int numberOfScales;
        private float regionMergeThreshold;

        #endregion

        #region Events

        public event ReportHandler Report;
        private event ShowJImageHandler ShowJImage;

        #endregion

        #region Constructors

        public JSEGAccessor()
            : this(CONSTQUANTTRESH, CONSTSCALES, CONSTMERGETRESH, true)
        {
        }

        public JSEGAccessor(int colorQuantizationThreshold, int numberOfScales, float regionMergeThreshold, bool saveJImages)
        {
            this.colorQuantizationThreshold = colorQuantizationThreshold;
            this.numberOfScales = numberOfScales;
            this.regionMergeThreshold = regionMergeThreshold;

            this.jImages = new List<JImage>();

            this.Report += new ReportHandler(ReportOnConsole);
            if (saveJImages)
            {
                this.ShowJImage += new ShowJImageHandler(SaveJImage);
            }
            
        }

        #endregion

        #region Properties

        public byte[,] ColorMap
        {
            get
            {
                return this.colorMap;
            }
        }

        public byte[,] RegionMap
        {
            get
            {
                return this.regionMap;
            }
        }

        public JImage[] JImages
        {
            get
            {
                return this.jImages.ToArray();
            }
        }

        #endregion

        #region Private Methods

        private void SaveJImage(int step, int TR, IntPtr ptr, int height, int width)
        {
            float[] J = new float[height * width];
            Marshal.Copy(ptr, J, 0, J.Length);
            JImage jImage = new JImage(step, TR, J, height, width);
            this.jImages.Add(jImage);
            Console.WriteLine(jImage.ToString());            
        }

        private void ReportOnConsole(string str)
        {
            Console.WriteLine(str);
        }

        #endregion

        #region Public Methods

        public void Process(Bitmap bitmap, Mode mode)
        {
            byte[] inputImage = new byte[bitmap.Height * bitmap.Width * 3];
            byte[] colorMapC = new byte[bitmap.Height * bitmap.Width];
            byte[] regionMapC = new byte[bitmap.Height * bitmap.Width];

            this.jImages.Clear();

            try
            {
                BitmapData data = bitmap.LockBits(new Rectangle(new Point(0, 0), bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
                bitmap.UnlockBits(data);
            }
            catch { }
            

            for (int y = 0, i = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    Color pixel = bitmap.GetPixel(x, y);
                    inputImage[i++] = pixel.R;
                    inputImage[i++] = pixel.G;
                    inputImage[i++] = pixel.B;
                }
            }

            try
            {
                ProcessImage(inputImage, bitmap.Height, bitmap.Width,
                    colorMapC, regionMapC,
                    this.colorQuantizationThreshold, this.numberOfScales, this.regionMergeThreshold,
                    (int)mode,
                    this.Report,
                    this.ShowJImage);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                throw ex;
            }

            this.colorMap = new byte[bitmap.Height, bitmap.Width];
            this.regionMap = new byte[bitmap.Height, bitmap.Width];

            for (int y = 0, i = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++, i++)
                {
                    this.colorMap[y, x] = colorMapC[i];
                    this.regionMap[y, x] = regionMapC[i];
                }
            }
        }

        #endregion
    }
}
